package jrain.fw.cfg.classpath;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import jrain.fw.core.cfg.CfgCallback;
import jrain.fw.core.cfg.CfgService;
import jrain.fw.core.service.DestroyService;
import jrain.fw.core.service.InitService;
import jrain.fw.core.service.Service;
import jrain.fw.core.service.ServiceConst;
import jrain.utils.collection.RDMap;
import jrain.utils.collection.RMap;
import jrain.utils.exception.ServiceException;

/**
 * <pre>
 * 作者：3244924214@qq.com 
 * 描述：类路径文件解析
 * </pre>
 */
@Service(group = ServiceConst.S_CFG_SERVICE, module = ServiceConst.M_CFG, dependency = ServiceConst.S_JSON_SERVICE)
public class CfgClasspathServcie implements CfgService, InitService, DestroyService {

	private static final Map<String, RMap<String, Object>> cfgMap = new HashMap<>();
	private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	private static final Map<String, List<CfgCallback>> callBackMap = new HashMap<>();
	private static final ReentrantReadWriteLock clock = new ReentrantReadWriteLock();
	private static final AtomicBoolean init = new AtomicBoolean(false);

	@Override
	public RMap<String, Object> getCfgMap(String module) {
		RMap<String, Object> rsMap = null;
		lock.readLock().lock();
		try {
			rsMap = cfgMap.get(module);
		} finally {
			lock.readLock().unlock();
		}
		if (rsMap == null) {
			throw new ServiceException("Configuration module cannot be empty! module=" + module);
		}
		return rsMap;
	}

	@Override
	public RMap<String, Object> getCfgMap(String module, RMap<String, Object> defaultMap) {
		lock.readLock().lock();
		try {
			RMap<String, Object> value = cfgMap.get(module);
			if (value == null) {
				return defaultMap;
			}
			return value;
		} finally {
			lock.readLock().unlock();
		}
	}

	@Override
	public Object getCfgValue(String module, String key) {
		return getCfgMap(module, new RDMap<>(new HashMap<>())).get(key);
	}

	@Override
	public Object getCfgValue(String module, String key, Object dvalue) {
		Object obj = getCfgMap(module, new RDMap<>(new HashMap<>())).get(key);
		if (obj == null) {
			return dvalue;
		}
		return obj;
	}

	@Override
	public void setCfgValue(String module, RMap<String, Object> dataMap) {
		lock.writeLock().lock();
		try {
			cfgMap.put(module, dataMap);
		} finally {
			lock.writeLock().unlock();
		}
		List<CfgCallback> list = null;
		clock.readLock().lock();
		try {
			list = callBackMap.get(module);
		} finally {
			clock.readLock().unlock();
		}
		if (list != null) {
			for (CfgCallback cfgCallback : list) {
				cfgCallback.callbak(module, dataMap);
			}
		}

	}

	@Override
	public void registerCfgCallBack(String module, CfgCallback callback) {
		clock.writeLock().lock();
		try {
			List<CfgCallback> list = callBackMap.get(module);
			if (list == null) {
				list = new ArrayList<>();
				callBackMap.put(module, list);
			}
			list.add(callback);
		} finally {
			clock.writeLock().unlock();
		}
	}

	@Override
	public void unregisterCfgCallBack(String module) {
		unregisterCfgCallBack(module, null);
	}

	@Override
	public void unregisterCfgCallBack(String module, CfgCallback callback) {
		clock.writeLock().lock();
		try {
			List<CfgCallback> list = callBackMap.get(module);
			if (callback != null) {
				list.remove(callback);
			} else {
				callBackMap.remove(module);
			}
		} finally {
			clock.writeLock().unlock();
		}
	}

	@Override
	public void init() {
		if (!init.getAndSet(true)) {
			Map<String, RMap<String, Object>> propMap = new CfgClasspathPropParser().parserCfg();
			cfgMap.putAll(propMap);
			Map<String, RMap<String, Object>> sqlMap = new CfgClasspathSqlParser().parserCfg();
			cfgMap.putAll(sqlMap);
			Map<String, RMap<String, Object>> validateMap = new CfgClasspathValidateParser().parserCfg();
			cfgMap.putAll(validateMap);
		}
	}

	@Override
	public void destroy() {
		if (init.get()) {
			lock.writeLock().lock();
			try {
				cfgMap.clear();
			} finally {
				lock.writeLock().unlock();
			}
			clock.writeLock().lock();
			try {
				callBackMap.clear();
			} finally {
				clock.writeLock().unlock();
			}
			init.set(false);
		}
	}

}
